#include <basic/errcode.h>
#include <basic/datetime.h>
#include <basic/log.h>

int log_from_stdout(char *log_file)
{/*{{{*/
    int fd;
    char log[LONG_FILE_NM_SIZE+1];

    if(log_file)
    {
        if(strlen(log_file) > LONG_FILE_NM_SIZE)
            return(-1);
        if(strcasecmp(log_file, "stdout") == 0)
            return(0);
        strcpy(log, log_file);
    }
    else
        strcpy(log, "/dev/null");
    fd=open(log, O_RDWR | O_CREAT | O_APPEND,
            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    if(fd == -1)  return(-2);
    close(1);
    dup(fd);
    close(fd);
    setbuf(stdout, NULL);

    return(0);
}/*}}}*/

enum { LOG_NONE, LOG_STDOUT, LOG_FILE };

struct _log
{/*{{{*/
    unsigned int type; 
    char file_nm[LONG_FILE_NM_SIZE];
    FILE *fp;

    unsigned int flag;
    char date[DATE_SIZE+1];
    pthread_mutex_t lock;
};/*}}}*/

int log_open(char *log_file, unsigned int flag, LOG *plog)
{/*{{{*/
    LOG log;

    if(!plog)
        return(RET_ERR_PARA);

    *plog=NULL;
    ALLOC_RETERR(log, struct _log, RET_ERR_ALLOC);

    if(!log_file)
    {
        log->type=LOG_NONE;
        goto GO_OUT;
    }

    if(strcasecmp(log_file, "stdout") == 0)
    {
        log->type=LOG_STDOUT;
        log->fp=stdout;
        goto GO_OUT;
    }

    if(log_file[0] == ZERO || strlen(log_file) > LONG_FILE_NM_SIZE)
    {
        free(log);
        return(RET_ERR_PARA);
    }
    log->type=LOG_FILE;
    strcpy(log->file_nm, log_file);
    log->fp=NULL;
    log->flag=flag;
    strcpy(log->date, MIN_DATE);
    if((log->flag & (LOG_DATE_SWITCH | LOG_MULTI_THREAD)) ==
            (LOG_DATE_SWITCH | LOG_MULTI_THREAD))
        pthread_mutex_init(&log->lock, NULL);
    if(!(log->flag & LOG_DATE_SWITCH))
    {
        if((log->fp=fopen(log->file_nm, "a")) == NULL)
        {
            free(log);
            return(RET_ERR_FILE_OPEN);
        }
        setbuf(log->fp, NULL);
    }

GO_OUT:
    *plog=log;
    return(0);
}/*}}}*/

void log_close(LOG log)
{/*{{{*/
    if(log)
    {
        if(log->type == LOG_FILE && log->fp)
            fclose(log->fp);
        free(log);
    }
}/*}}}*/

static int _date_switch(LOG log)
{/*{{{*/
    char curr_dt[DATE_SIZE+1];

    curr_date(curr_dt);
    if(strcmp(log->date, curr_dt) != 0)
    {
        char file_nm[LONG_FILE_NM_SIZE+1];

        if(log->fp)  fclose(log->fp);
        sprintf(file_nm, "%s.%s", log->file_nm, curr_dt);
        if((log->fp=fopen(file_nm, "a")) == NULL)
            return(-1);
        strcpy(log->date, curr_dt);
        setbuf(log->fp, NULL);
    }
    return(0);
}/*}}}*/

int log_write(LOG log, char *format, ...)
{/*{{{*/
    va_list arglist;
    int rtn=0;

    if(!log)
        return(RET_ERR_PARA);
    if(log->type == LOG_NONE || !format)
        return(0);

    // 日期切换
    if(log->flag & LOG_DATE_SWITCH)
    {
        // 多线程
        if(log->flag & LOG_MULTI_THREAD)
            pthread_mutex_lock(&log->lock);
        if(_date_switch(log) == 0)
        {
            va_start(arglist, format);
            vfprintf(log->fp, format, arglist);
        }
        else
            rtn=-1;
        // 多线程
        if(log->flag & LOG_MULTI_THREAD)
            pthread_mutex_unlock(&log->lock);
    }
    else
    {
        va_start(arglist, format);
        vfprintf(log->fp, format, arglist);
    }

    return(rtn);
}/*}}}*/

int log_write_raw(LOG log, char *msg)
{/*{{{*/
    int rtn=0;

    if(!log)
        return(RET_ERR_PARA);
    if(log->type == LOG_NONE || !msg)
        return(0);

    // 日期切换
    if(log->flag & LOG_DATE_SWITCH)
    {
        // 多线程
        if(log->flag & LOG_MULTI_THREAD)
            pthread_mutex_lock(&log->lock);
        if(_date_switch(log) == 0)
        {
            fputs(msg, log->fp);
        }
        else
            rtn=-1;
        // 多线程
        if(log->flag & LOG_MULTI_THREAD)
            pthread_mutex_unlock(&log->lock);
    }
    else
    {
        fputs(msg, log->fp);
    }

    return(rtn);
}/*}}}*/
